import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter_common/util/logger.dart';
import 'package:flutter_common/util/string_utils.dart';
import 'package:path_provider/path_provider.dart';
import 'package:visibility_detector/visibility_detector.dart';

int _count = 0;

///该视图展示在屏幕内才请求加载图片
class LazyImage extends StatefulWidget {

  final String? filePath;
  final String? imageUrl;
  final Future<String>? futureUrl;
  final String? assetName;
  final num? width;
  final num? height;
  final BoxFit? fit;
  final num? cacheWidth;
  final num? cacheHeight;

  LazyImage(
      {super.key,
      String? filePath,
      this.imageUrl,
      this.assetName,
      this.futureUrl,
      this.width,
      this.height,
      this.fit,
      this.cacheWidth,
      this.cacheHeight})
      : filePath = "".equals(filePath) ? null : filePath;

  @override
  State<StatefulWidget> createState() => _ImageState();
  
}

class _ImageState extends State<LazyImage> {

  ValueKey? key;
  bool showInUI = false;

  @override
  void initState() {
    super.initState();
    String? keyValue = widget.imageUrl ?? widget.filePath ?? widget.assetName;
    if(keyValue == null) {
      if(widget.futureUrl == null) return;
      keyValue = hashCode.toString();
    }
    key = ValueKey(keyValue);
  }

  _placeholder() {
    return SizedBox(
        width: widget.width?.toDouble(), height: widget.height?.toDouble());
  }

  @override
  Widget build(BuildContext context) {
    if (key == null) {
      return _placeholder();
    }
    Widget w = FutureBuilder(
      future: loadImage(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return snapshot.data as Widget;
        } else {
          return _placeholder();
        }
      },
    );
    return VisibilityDetector(
        key: key!,
        child: w,
        onVisibilityChanged: (info) {
          showInUI =
              info.visibleBounds.height > 10 || info.visibleBounds.width > 10;
          // print("${info.visibleBounds.height} ${info.visibleBounds.width} $showInUI");
          if (mounted) {
            setState(() {});
          }
        });
  }

  String? _hashId() {
    return Object.hash(key!.value, widget.cacheWidth, widget.cacheHeight).toRadixString(16);
  }

  Future<Widget> loadImage() async {
    if (showInUI == false) {
      return _placeholder();
    }

      Widget? w;
      ImageProvider? image;
      if (widget.filePath != null) {
        _count++;
        image = await _handleLocalImage();
        _count--;
      } else if (widget.imageUrl != null) {
        image = NetworkImage(widget.imageUrl!, scale: 1);
      } else if (widget.assetName != null) {
        image = AssetImage(widget.assetName!);
      } else if (widget.futureUrl != null) {
        String p = await widget.futureUrl!;
        if(p.startsWith(RegExp('http[s]://'))) {
          image = NetworkImage(p, scale: 1);
        } else {
          _count++;
          image = await _handleLocalImage();
          _count--;
        }
      }
      if (image != null) {
        int? cacheWidth = widget.cacheWidth?.toInt();
        int? cacheHeight =  widget.cacheHeight?.toInt();
        image = ResizeImage.resizeIfNeeded(cacheWidth, cacheHeight, image);
        w = Image(
          image: image,
          width: widget.width?.toDouble(),
          height: widget.height?.toDouble(),
          fit: widget.fit,
        );
      }
      if (w != null) {
        return w;
      }
      return _placeholder();
  }

  Future<ImageProvider?> _handleLocalImage() async {
    /// 内存中加载的图片超过5张，就不继续加载了，免的爆内存
    if(_count > 6) return null;
    if(widget.cacheWidth != null && widget.cacheHeight != null) {
      String tmp = await getTemporaryPath();
      String path = "$tmp/tmp/lazy_${_hashId()}.jpg";
      logger.debug("LazyImage path: $path");
      File file = File(path);
      if (await file.exists()) {
        return FileImage(file);
      } else {
        file.parent.create(recursive: true);
        bool success = await thumbnailImage(widget.filePath!, path, widget.cacheWidth!.toInt(), widget.cacheHeight!.toInt());
        if (success) {
          return FileImage(file);
        }
      }
    } else {
      return FileImage(File(widget.filePath!));
    }
    return null;
  }
}